//
// Created by 16933 on 2024/1/13.
//

#include "bsp_I2C.h"
/*! 发送开始信号
 * 该信号的判定条件：SCL高电平期间，SDA从高电平切换到低电平
 * 该信号前SCL与SDA的状态：  1.初始的时候出现：SCL、SDA空闲，被上拉，两者都为高电平(1)
 *                       2.在读取应答信号之后重新开始一帧数据时出现：此时SDA可能为高电平也可能为低电平 SCL为低电平(0)
 * 该信号后SCL与SDA的状态： SDA为0  SCL为0   总线忙
 * */

void I2C_Start(I2C_t *i2c_device)
{
    DA_UP(i2c_device);               //保证SDA为高电平
    CL_UP(i2c_device);
    DELAY();
    DA_DOWN(i2c_device);
    DELAY();        //至少保持0.6us
    CL_DOWN(i2c_device);             //钳住I2C总线，准备发送或接收
}

/*!  发送结束信号
 * 该信号的判定条件：SCL高电平期间，SDA从低电平切换到高电平
 * 该信号前SCL与SDA的状态：  1. 跟在产生应答信号之后    SDA可能是0 可能是1   我们掌握总线控制权 所以SCL为0
 *                       2. 跟在读取应答信号之后    SDA可能是0 可能是1    我们掌握总线控制权 所以SCL为0
 * 该信号后SCL与SDA的状态： SDA为1  SCL为1  符合空闲状态
 * */
void I2C_Stop(I2C_t *i2c_device)
{
    DA_DOWN(i2c_device);         //保证SDA低电平从而可以产生上升沿
    CL_UP(i2c_device);
    DELAY();
    DA_UP(i2c_device);
    DELAY();
}


/*! 发送应答信号
 * 该信号的判定条件：SDA低电平期间 SCL拉高再拉低
 * 该信号前SCL与SDA的状态：跟在发送数据之后    SDA可能为0 可能为1， 我们掌握总线控制权 所以SCL为0
 * */
void I2C_Send_ACK(I2C_t *i2c_device)
{
    DA_DOWN(i2c_device);
    CL_UP(i2c_device);
    DELAY();
    CL_DOWN(i2c_device);
}

/*! 发送非应答信号
 * 该信号的判定条件：SDA低电平期间 SCL拉高再拉低
 * 该信号前SCL与SDA的状态：跟在发送数据之后    SDA可能为0 可能为1， 我们掌握总线控制权 所以SCL为0
 * */
void I2C_Send_NACK(I2C_t *i2c_device)
{
    DA_UP(i2c_device);
    CL_UP(i2c_device);
    DELAY();
    CL_DOWN(i2c_device);
}

/*! 等待应答信号 */
uint8_t I2C_Wait_ACK(I2C_t *i2c_device)
{
    uint8_t ACK = 0;
    DA_UP(i2c_device);                   //释放SDA总线
    CL_UP(i2c_device);                   //SCL拉高时期可以进行读取
    DELAY();                    //给它从设备点反应时间0
    ACK = DA_READ(i2c_device);
    CL_DOWN(i2c_device);
    return ACK;
}


/*! 发送一个字节数据 */
void I2C_Send_Byte(I2C_t *i2c_device , uint8_t Byte)
{
    uint8_t i;
    for (i=0; i < 8; i++) {
        if (Byte&(0x80>>i))     //发1   can总线上时高位先行
        {
            DA_UP(i2c_device);
            CL_UP(i2c_device);
            delay_us(1);  // 最低时间为0.4us  要保证可以读取到
            CL_DOWN(i2c_device);
        } else                  //发0
        {
            DA_DOWN(i2c_device);
            CL_UP(i2c_device);
            delay_us(1);
            CL_DOWN(i2c_device);
        }

    }
}


/*! 接收一个字节数据 并发送ACK*/

uint8_t I2C_Receive_Byte(I2C_t *i2c_device , uint8_t  ack)
{
    uint8_t Byte = 0x00;
    uint8_t i;
    DA_UP(i2c_device);    //释放SDA总线

    for (i = 0; i < 8; i++) {
        CL_UP(i2c_device);


        if (DA_READ(i2c_device)) //读到1
        {

            Byte|=(0x80>>i);
        }
        CL_DOWN(i2c_device);

    }
    if (!ack)
    {
        I2C_Send_NACK(i2c_device);

    } else
    {
        I2C_Send_ACK(i2c_device);
    }
    return Byte;
}

/*! @brief 连续写多个字节
 * @param addr：外设地址
 * @param len：写入长度
 * @param buf：写入的数据
 * @return 1:失败  0：成功
 * */
uint8_t I2C_Write_Bytes(I2C_t *i2c_device , uint8_t addr,uint8_t len,uint8_t *buf)
{
    uint8_t i;
    I2C_Start(i2c_device);
    I2C_Send_Byte(i2c_device , addr << 1);
    if (I2C_Wait_ACK(i2c_device))
    {
        I2C_Stop(i2c_device);
        return 1 ;
    }
//    I2C_Send_Byte(reg);
//    I2C_Wait_ACK();
    for (i = 0;i<len;i++) {
        I2C_Send_Byte(i2c_device , buf[i]);
        if (I2C_Wait_ACK(i2c_device))
        {
            I2C_Stop(i2c_device);
            return 1 ;
        }
    }
    I2C_Stop(i2c_device);
    return 0;

}

/*!
 * @brief 连续读取多个字节数据
 * @param addr：外设地址
 * @param reg：寄存器地址
 * @param len：写入长度
 * @param buf：数据存储地址
 * @return 1:失败  0：成功
 * */
uint8_t I2C_Read_Bytes(I2C_t *i2c_device , uint8_t addr,uint8_t len,uint8_t *buf)
{
    I2C_Start(i2c_device);
//    I2C_Send_Byte(reg << 1);
//    if (I2C_Wait_ACK())
//    {
//        I2C_Stop();
//        return 1 ;
//    }
//    I2C_Send_Byte(reg);
//    I2C_Wait_ACK();
//    I2C_Start();
    I2C_Send_Byte(i2c_device , (addr << 1) | 0x01);
    I2C_Wait_ACK(i2c_device);
    while(len)
    {
        if (len==1)
        {
            *buf = I2C_Receive_Byte(i2c_device , 0);

        }
        else
        {
            *buf = I2C_Receive_Byte(i2c_device , 1);
        }
        len--;
        buf++;

    }
    I2C_Stop(i2c_device);
    return 0;
}





void delay_us(uint32_t us)
{
    uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
    while (delay--)
    {
        ;
    }
}

void delay_ms(uint32_t ms)
{
    uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * (1000*ms));
    while (delay--)
    {
        ;
    }
}